import {highlight} from "~api/highlightText/highlight";
import {addHighlightError} from "~api/highlightError/lost";

const loadHighlightText = (highlightVal, highlightIndex, noErrorTracking) => {
  console.log("loading highlight text...");
  const selection = {
    anchorNode: elementFromQuery(highlightVal.anchorNode),
    anchorOffset: highlightVal.anchorOffset,
    focusNode: elementFromQuery(highlightVal.focusNode),
    focusOffset: highlightVal.focusOffset,
  };
  console.log(`anchorNode query: ${highlightVal.anchorNode}`);
  console.log(`focusNode query: ${highlightVal.focusNode}`);

  const { color, string: selectionString, textColor, ver, viewstate } = highlightVal;
  const container = elementFromQuery(highlightVal.container);

  if (!selection.anchorNode || !selection.focusNode || !container) {
    if (!noErrorTracking) {
      addHighlightError(highlightVal, highlightIndex);
    }
    return false;
  }

  console.log("highlighting text...");
  const success = highlight(selectionString, container, selection, color, textColor, highlightIndex, viewstate, ver);
  console.log(`highlighting text: ${success}`);

  if (!noErrorTracking && !success) {
    addHighlightError(highlightVal, highlightIndex);
  }
  return success;
}

const elementFromQuery = (storedQuery) => {
  const re = />textNode:nth-of-type\(([0-9]+)\)$/ui;
  const result = re.exec(storedQuery);

  if (result) { // For text nodes, nth-of-type needs to be handled differently (not a valid CSS selector)
    const textNodeIndex = parseInt(result[1], 10);
    storedQuery = storedQuery.replace(re, "");
    const parent = robustQuerySelector(storedQuery);

    if (!parent) return undefined;

    return parent.childNodes[textNodeIndex];
  }

  return robustQuerySelector(storedQuery);
}

const robustQuerySelector = (query) => {
  try {
    return document.querySelector(query);
  } catch (error) {
    // It is possible that this query fails because of an invalid CSS selector that actually exists in the DOM.
    // This was happening for example here: https://lawphil.net/judjuris/juri2013/sep2013/gr_179987_2013.html
    // where there is a tag <p"> that is invalid in HTML5 but was still rendered by the browser
    // In this case, manually find the element:
    let element = document;
    for (const queryPart of query.split(">")) {
      if (!element) return null;

      const re = /^(.*):nth-of-type\(([0-9]+)\)$/ui;
      const result = re.exec(queryPart);
      const [, tagName, index] = result || [undefined, queryPart, 1];
      element = Array.from(element.childNodes).filter((child) => child.localName === tagName)[index - 1];
    }
    return element;
  }
}

export default loadHighlightText;
